#include <stdio.h>
#include <string.h>

#include "protocol.h"
#include "datalink.h"

#define DATA_TIMER  2000
#define MAX_SEQ     7 // 假设序号范围为 0-7，窗口大小不能超过 MAX_SEQ
#define SEND_WINDOW_SIZE 4 // 发送窗口大小，应小于等于 MAX_SEQ

struct FRAME { 
    unsigned char kind; 
    unsigned char ack;  // 在GBN中，ACK帧的ack字段表示期望收到的下一帧序号
    unsigned char seq;  // 数据帧的序号
    unsigned char data[PKT_LEN]; 
    unsigned int  padding;
};

// GBN 状态变量
static unsigned char next_frame_to_send = 0; // 下一个要发送的帧的序号
static unsigned char ack_expected = 0;     // 发送方：期望收到的ACK（基序号）
static unsigned char frame_expected = 0;   // 接收方：期望收到的数据帧序号
static struct FRAME send_buffer[MAX_SEQ + 1]; // 发送缓冲区，存储已发送但未确认的帧
static int nbuffered = 0; // 发送缓冲区中帧的数量 (窗口中已发送的帧数)
static int phl_ready = 0;

// 辅助函数：判断序号是否在窗口内
static int between(unsigned char a, unsigned char b, unsigned char c) {
    // a <= b < c (circularly)
    return ((a <= b) && (b < c)) || ((c < a) && (a <= b)) || ((b < c) && (c < a));
}

static void put_frame(unsigned char *frame, int len)
{
    *(unsigned int *)(frame + len) = crc32(frame, len);
    send_frame(frame, len + 4);
    phl_ready = 0;
}

// 发送数据帧（窗口内的帧）
static void send_data_frame_gbn(unsigned char frame_nr, unsigned char frame_expected_by_receiver)
{
    struct FRAME *s = &send_buffer[frame_nr]; // 从缓冲区获取要发送的帧

    s->kind = FRAME_DATA;
    s->seq = frame_nr;
    s->ack = (frame_expected_by_receiver + MAX_SEQ) % (MAX_SEQ + 1); // Piggyback ACK
    // s->data 已经在 get_packet 时填充到 send_buffer 中

    dbg_frame("Send DATA %d, ACK %d, ID %d\n", s->seq, s->ack, *(short *)s->data);

    put_frame((unsigned char *)s, 3 + PKT_LEN);
    start_timer(frame_nr, DATA_TIMER); // 为每个发送的帧启动定时器 (或者只为最早未确认的帧启动一个定时器)
}

// 发送 ACK 帧
static void send_ack_frame_gbn(void)
{
    struct FRAME s_ack;
    s_ack.kind = FRAME_ACK;
    s_ack.ack = frame_expected; // ACK 期望收到的下一帧序号

    dbg_frame("Send ACK %d\n", s_ack.ack);
    put_frame((unsigned char *)&s_ack, 2);
}

// 重传从指定序号开始的所有未确认帧
static void retransmit_frames(void) {
    unsigned char i = ack_expected;
    while (between(ack_expected, i, next_frame_to_send)) {
        dbg_event("---- Retransmitting DATA %d timeout ----\n", i);
        send_data_frame_gbn(i, frame_expected); // 注意：这里的 frame_expected 是接收方期望的，可能需要调整
        i = (i + 1) % (MAX_SEQ + 1);
    }
}

int main(int argc, char **argv)
{
    int event, arg;
    struct FRAME f_recv;
    int len = 0;

    protocol_init(argc, argv); 
    lprintf("Designed by Jiang Yanjun (GBN Modification), build: " __DATE__"  "__TIME__"\n");

    enable_network_layer(); // GBN 通常允许网络层持续提供数据

    for (;;) {
        event = wait_for_event(&arg);

        switch (event) {
        case NETWORK_LAYER_READY: // 网络层有数据包
            if (nbuffered < SEND_WINDOW_SIZE) { // 如果窗口未满
                // 从网络层获取数据包并存入发送缓冲区
                get_packet(send_buffer[next_frame_to_send].data);
                nbuffered++;
                send_data_frame_gbn(next_frame_to_send, frame_expected); // 发送新的数据帧
                next_frame_to_send = (next_frame_to_send + 1) % (MAX_SEQ + 1);
            } else {
                // 窗口已满，暂时禁用网络层，防止数据包堆积
                // disable_network_layer(); // 或者让上层等待
            }
            break;

        case PHYSICAL_LAYER_READY:
            phl_ready = 1;
            // GBN 中，物理层就绪通常意味着可以发送更多帧，如果窗口允许
            // 可以在这里检查是否可以发送 next_frame_to_send
            break;

        case FRAME_RECEIVED: 
            len = recv_frame((unsigned char *)&f_recv, sizeof f_recv);
            if (len < 5 || crc32((unsigned char *)&f_recv, len) != 0) {
                dbg_event("**** Receiver Error, Bad CRC Checksum\n");
                // GBN 接收方通常忽略错误帧
                break;
            }

            if (f_recv.kind == FRAME_DATA) {
                dbg_frame("Recv DATA %d, ACK %d, ID %d\n", f_recv.seq, f_recv.ack, *(short *)f_recv.data);
                if (f_recv.seq == frame_expected) { // 收到了期望的数据帧
                    put_packet(f_recv.data, PKT_LEN); // 将数据交给网络层
                    frame_expected = (frame_expected + 1) % (MAX_SEQ + 1); // 更新期望的下一帧序号
                }
                // 无论是否是期望的帧，都发送对正确接收到的最高连续帧的确认
                // GBN 的 ACK 是累积确认，确认号表示期望收到的下一帧
                send_ack_frame_gbn(); 
            }

            // 处理 piggybacked ACK 或者单独的 ACK 帧
            // GBN 的 ACK 是累积的，ack_expected 是发送窗口的基序号
            // 如果收到的 f_recv.ack (表示对方期望的下一帧) > ack_expected，则滑动窗口
            if (f_recv.kind == FRAME_ACK || (f_recv.kind == FRAME_DATA && len > 2 /* piggybacked ACK */)) {
                 dbg_frame("Recv ACK/PiggyACK for %d\n", f_recv.ack);
                while (between(ack_expected, f_recv.ack, next_frame_to_send)) {
                    nbuffered--; // 释放缓冲区空间
                    stop_timer(ack_expected); // 停止对应帧的定时器
                    ack_expected = (ack_expected + 1) % (MAX_SEQ + 1); // 滑动窗口
                    // enable_network_layer(); // 窗口有空间了，可以允许网络层发送
                }
            }
            break; 

        case DATA_TIMEOUT: // 定时器超时
            // arg 通常是超时的帧序号
            // GBN: 如果是最早未确认的帧超时，则重传从 ack_expected 开始的所有已发送未确认的帧
            // 或者，如果为每个帧都启动了定时器，那么 arg 就是超时的那个帧的序号
            // 简单处理：假设超时的是 ack_expected (最早未确认的帧)
            // 或者，如果 arg 是超时的帧序号，且该帧仍在窗口内（即未被确认）
            if (arg == ack_expected || between(ack_expected, (unsigned char)arg, next_frame_to_send) ) { 
                 dbg_event("---- DATA %d (or base %d) timeout ----\n", arg, ack_expected);
                 // 停止所有活动定时器，然后重传
                 unsigned char temp_seq = ack_expected;
                 while(between(ack_expected, temp_seq, next_frame_to_send)){
                     stop_timer(temp_seq);
                     temp_seq = (temp_seq + 1) % (MAX_SEQ + 1);
                 }
                 // 从 ack_expected 开始重传窗口内的所有帧
                 next_frame_to_send = ack_expected; // 重置发送指针到窗口基部
                 for(int k=0; k < nbuffered; ++k) { // nbuffered 是当前窗口中实际的帧数
                     send_data_frame_gbn(next_frame_to_send, frame_expected);
                     next_frame_to_send = (next_frame_to_send + 1) % (MAX_SEQ + 1);
                 }
                 // 如果没有帧在飞，则 next_frame_to_send 保持不变，nbuffered 为 0
            }
            break;
        }

        // 控制网络层是否可以发送数据
        if (nbuffered < SEND_WINDOW_SIZE && phl_ready) {
            enable_network_layer();
        } else {
            disable_network_layer();
        }
   }
}
